#include <stdlib.h>
#include <assert.h>

#include "ci_task.h"

#include "MemPool.h"
#include <malloc.h>

extern "C" void aceMesh_task_constructor(struct aceMesh_task* self);
extern "C" void aceMesh_task_destructor(aceMesh_task *p_acemesh_task);
extern "C" void *my_malloc_aligned(int size);

void ci_task_constructor(ci_task *self, TASK_FUNCPTR funcptr) {
    aceMesh_task_constructor(&(self->aceMesh_task_base));
    self->slave_ci_task_func = funcptr;
    self->neighbor_isdefine = 0;
}

#ifdef DOUBLE_FUNC
void ci_task_constructor_msfunc(ci_task *self, TASK_FUNCPTR mfuncptr,TASK_FUNCPTR sfuncptr ) {
    aceMesh_task_constructor(&(self->aceMesh_task_base));
    self->master_ci_task_func = mfuncptr;
    self->slave_ci_task_func = sfuncptr;
    self->neighbor_isdefine = 0;
}
#endif

void ci_task_destructor(ci_task *p_ci_task) {
    aceMesh_task_destructor(&p_ci_task->aceMesh_task_base);
#ifndef MEMORY_POOL
    if (p_ci_task->ci_args != NULL) {
#ifdef TARG_SW5
        free(p_ci_task->ci_args);
#elif TARG_SW9
        my_free_aligned(p_ci_task->ci_args);
#else
        printf("losing free ci_task_args\n");
#endif

    }
#ifdef TARG_SW5
    free(p_ci_task);
#elif TARG_SW9
    my_free_aligned(p_ci_task);
#else
    printf("losing free ci_task\n");
#endif
#endif
}

void define(ci_task *self, void *a_args, unsigned int args_size) {
#ifdef MEMORY_POOL
#ifdef USE_SIMD
#ifdef TARG_SW5
    self->ci_args = acemesh_myalloc_aligned_32(args_size);
#elif TARG_SW9
   //printf("before_ci_args_aligned\n");
    self->ci_args = acemesh_myalloc_aligned_64(args_size);
 //  printf("after_ci_args_aligned\n");
#endif
#else
    self->ci_args = acemesh_myalloc_aligned_16(args_size);
#endif
#else
#ifdef TARG_SW5
    self->ci_args = malloc(args_size);
#elif TARG_SW9
    self->ci_args = my_malloc_aligned(args_size);
#else
    assert(0);
#endif
#endif
    memcpy(self->ci_args, a_args, args_size);
}

void define_neighbors(ci_task *self, void *cxx_this_pointer, void *a_get_neighbors,
                      void *a_neighbor_args) {
    self->ci_cxx_this_pointer = cxx_this_pointer;
    self->ci_get_neighbors = a_get_neighbors;
    self->ci_neighbor_args = a_neighbor_args;
    self->neighbor_isdefine = 1;
}

void get_neighbor(ci_task *self, int neighbor, void *src_addr, void **neighbor_addrs, int *num_neigh) {
    if (self->neighbor_isdefine) {
        if (self->ci_cxx_this_pointer == NULL) {
#ifndef SWF
            NEIGHBOR_FUNCPTR fp = (NEIGHBOR_FUNCPTR)(self->ci_get_neighbors);
            fp(neighbor_addrs, num_neigh, self->ci_neighbor_args);
#else
            TASK_FUNCPTR fp = (TASK_FUNCPTR)(self->ci_get_neighbors);
            fp(self->ci_neighbor_args);
#endif
        }
#ifdef TEMP_ASSERT
         else
            assert(0);
#endif
    }
}
